#define NOMINMAX
#include "work_channel.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/rand_util.h"
#include "base/process_util.h"
#include "base/message_loop.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_channel_proxy.h"

namespace dl {

// IPC::Listener回调与创建WorkChannel对象
// 在一个线程环境(当前都在主线程)
// 使用ChannelProxy是为了让消息发送和接收的处理扔到指定的IO线程中
// 从而避免阻塞当前线程(指定的IO线程将接收到的消息处理完抛给当前线程)
// WorkChannel::Pimpl
struct WorkChannel::Pimpl : public IPC::Listener{
  Pimpl(WorkChannel* h, ConnectTransfer* ct, MessageTransfer* mt);
  // IPC::Listener
  virtual bool OnMessageReceived(const IPC::Message& message);
  virtual void OnChannelConnected(int32 peer_pid);
  virtual void OnChannelError();

  WorkChannel* host;
  scoped_ptr<IPC::ChannelProxy> channel;
  ConnectTransfer* connect_transfer;
  MessageTransfer* message_transfer;
  int32  process;
};

WorkChannel::Pimpl::Pimpl(WorkChannel* h, ConnectTransfer* ct, MessageTransfer* mt) {
  host              = h;
  connect_transfer  = ct;
  message_transfer  = mt;
  process           = 0;
}

// IPC::Listener
bool WorkChannel::Pimpl::OnMessageReceived(const IPC::Message& message) {
  return message_transfer->OnMessageDispatch(host, message);
}

void WorkChannel::Pimpl::OnChannelConnected(int32 peer_pid) {
  process = peer_pid;
  connect_transfer->OnConnectArrived(host, peer_pid);
}

void WorkChannel::Pimpl::OnChannelError() {
  connect_transfer->OnConnectError(host);
}

// WorkChannel
WorkChannel::WorkChannel(const std::string& name, MessageLoop* message_loop, 
    ConnectTransfer* connect_transfer, MessageTransfer* message_transfer) {
  pimpl_.reset(new Pimpl(this, connect_transfer, message_transfer));
  pimpl_->channel.reset(new IPC::ChannelProxy(
      name, IPC::Channel::MODE_CLIENT, pimpl_.get(), message_loop->message_loop_proxy()));
}

WorkChannel::~WorkChannel() {
}

int32  WorkChannel::PeerProcessID() const {
  return pimpl_->process;
}

void WorkChannel::Send(IPC::Message* message) {
	pimpl_->channel->Send(message);
}

}
